package com.zengqingfa.examples.mybatisplus.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.zengqingfa.examples.mybatisplus.annotation.FieldAuth;
import com.zengqingfa.examples.mybatisplus.annotation.FieldAuth2;
import com.zengqingfa.examples.mybatisplus.dto.DynamicColumnInfoDTO;
import com.zengqingfa.examples.mybatisplus.enums.DynamicColumnModuleEnum;
import com.zengqingfa.examples.mybatisplus.service.IDynamicColumnService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @fileName: FieldAuthAspect
 * @author: zengqf3
 * @date: 2022-4-6 15:20
 * @description: 字段权限注解
 */
@Component
@Aspect
@Slf4j
public class FieldAuthAspect2 {

    @Resource
    private IDynamicColumnService dynamicColumnService;


    //拦截 FieldAuth注解
    @Pointcut("@annotation(com.zengqingfa.examples.mybatisplus.annotation.FieldAuth2)")
    private void fieldAuthPointCut() {
        //logHistoryPointCut 日志注解切点
    }

    @Around("fieldAuthPointCut()")
    public Object fieldAuthAround(ProceedingJoinPoint pjp) {
        //获取参数
        Object[] args = pjp.getArgs();
        log.info("参数args:{}", args);
        //获取方法
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        // 获取FieldAuth注解
        FieldAuth2 fieldAuth = method.getAnnotation(FieldAuth2.class);
        Object returnVal = null;
        try {
            //执行方法
            returnVal = pjp.proceed();
            if (fieldAuth != null) {
                //获取到请求的request
                HttpServletRequest request =
                        ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
                String userCode = request.getHeader("userCode");
                if (StringUtils.isNotBlank(userCode)) {
                    //如果有字段权限注解，则需要修改返回值
                    DynamicColumnModuleEnum moudle = fieldAuth.moudle();
                    Class clazz = fieldAuth.clazz();
                    List<DynamicColumnInfoDTO> columnInfos = dynamicColumnService.queryDynamicColumn(moudle.getType(), userCode);
                    //获取到字段
                    List<String> fields = columnInfos.stream().map(DynamicColumnInfoDTO::getField).distinct().collect(Collectors.toList());
                    //fastjson过滤器：FastJson的属性过滤器
                    /**
                     * https://www.cnblogs.com/pcheng/p/11507901.html
                     * 通过实现PropertyFilter接口的apply方法，来实现过滤属性，方法参数name即为字段的key，参数value即为字段的value，这种方式最强大，因为可以自定义具体过滤规则。
                     * 方法返回false即为排除该字段。在转JSON的时候，带上过滤器参数即可。注：参数name指的字段名为转成JSON后的key，不是实体的属性名。
                     */
                    PropertyFilter profilter = new PropertyFilter() {
                        @Override
                        public boolean apply(Object object, String name, Object value) {
                            if (fields.contains(name)) {
                                // false表示字段将被排除在外
                                return true;
                            }
                            return false;
                        }
                    };
                    //判断分页还是直接的map,只支持IPage<Map> 和List<Map>
                    if (returnVal instanceof IPage) {
                        IPage mapIPage = (IPage) returnVal;
                        //重新序列化为json需要的字段返回
                        IPage pageResult = new Page(mapIPage.getCurrent(), mapIPage.getSize(), mapIPage.getTotal());
                        pageResult.setPages(mapIPage.getPages());
                        List<?> records = mapIPage.getRecords();
                        if (CollectionUtils.isEmpty(records)) {
                            return pageResult;
                        }
                        List<Object> results = Lists.newArrayList();
                        records.forEach(r -> {
                            String s = JSON.toJSONString(r, profilter);
                            Object o = JSONObject.parseObject(s, clazz);
                            results.add(o);
                        });
                        pageResult.setRecords(results);
                        return pageResult;
                    } else if (returnVal instanceof List) {
                        List<?> records = (List<?>) returnVal;
                        //重新序列化为json需要的字段返回
                        if (CollectionUtils.isEmpty(records)) {
                            return records;
                        }
                        List<Object> results = Lists.newArrayList();
                        records.forEach(r -> {
                            String s = JSON.toJSONString(r, profilter);
                            Object o = JSONObject.parseObject(s, clazz);
                            results.add(o);
                        });
                        return results;
                    }
                }
            }
        } catch (Throwable e) {
            log.error("e:{}", e.getMessage());
        }
        //执行方法后
        return returnVal;
    }

}
